/*
 * DexVerify.c
 *
 *  Created on: 2011-7-8
 *      Author: gexiao
 */
#include "../Dalvik.h"
#include "CodeVerify.h"

//fwd
static bool computeCodeWidths(const Method* meth, InsnFlags* insnFlags,
		int* pNewInstanceCount);
static bool verifyMethod(Method* meth, int verifyFlags);

/*
 * Initialize some things we need for verification.
 */bool dvmVerificationStartup(void) {
	gDvm.instrWidth = dexCreateInstrWidthTable();
	gDvm.instrFormat = dexCreateInstrFormatTable();
	gDvm.instrFlags = dexCreateInstrFlagsTable();
	if (gDvm.instrWidth == NULL || gDvm.instrFormat == NULL || gDvm.instrFlags
			== NULL) {
		//LOGE("Unable to create instruction tables\n");
		return false;
	}

	return true;
}

/*
 * Verify a class.
 *
 * By the time we get here, the value of gDvm.classVerifyMode should already
 * have been factored in. If you want to call into the verifier even
 * though verification is disabled, that's your business.
 *
 * Return "true" on success.
 */bool dvmVerifyClass(ClassObject* clazz, int verifyFlags) {
	int i;

	if (dvmIsClassVerified(clazz)) {
		return true;
	}

	//TODO - verify class structure in DEX?

}

/*
 * Perform verification on a single method.
 *
 * We do this in three passes:
 *  (1) Walk through all code units, determining instruction lengths.
 *  (2) Do static checks, including branch target and operand validation.
 *  (3) Do structural checks, including data-flow analysis.
 *
 * Some checks may be bypassed depending on the verification mode. We can't
 * turn this stuff off completely if we want to do "exact" GC.
 *
 * - operands of getfield, putfield, getstatic, putstatic must be valid
 * - operands of method invocation instructions must be valid
 *
 * - code array must not be empty
 * - (N/A) code_length must be less than 65536
 * - opcode of first instruction begins at index 0
 * - only documented instructions may appear
 * - each instruction follows the last
 * - (below) last byte of last instruction is at (code_length-1)
 */
static bool verifyMethod(Method* meth, int verifyFlags) {
	bool result = false;
	UninitInstanceMap* uninitMap = NULL;
	InsnFlags* insnFlags = NULL;
	int i, newInstanceCount;

	/*
	 * If there aren't any instructions, make sure that's expected, then
	 * exit successfully. Note: meth->insns gets set to a native function
	 * pointer on first call.
	 */
	if (dvmGetMethodInsnsSize(meth) == 0) {
		if (!dvmIsNativeMethod(meth) && !dvmIsAbstractMethod(meth)) {
			goto bail;
		}

		goto success;
	}

	/*
	 * Allocate and populate an array to hold instruction data.
	 *
	 * TODO: Consider keeping a reusable pre-allocated array sitting
	 * around for smaller methods.
	 */
	insnFlags = (InsnFlags*) calloc(dvmGetMethodInsnsSize(meth),
			sizeof(InsnFlags));
	if (insnFlags == NULL) {
		goto bail;
	}

	/*
	 * Compute the width of each instruction and store the result in insnFlags.
	 * Count up the #if occurrences of new-instance instructions while we're
	 * at it.
	 */

	success: result = true;
	bail: dvmFreeUninitInstanceMap(uninitMap);
	free(insnFlags);
	return result;
}

/*
 * Compute the width of the instruction at each address in the instruction
 * stream. Addresses that are in the middle of an instruction, or that
 * are part of switch table data, are not set(so the caller should probably
 * initialize "insnFlags" to zero).
 *
 * Logs an error and returns "false" on failure.
 */
static bool computeCodeWidths(const Method* meth, InsnFlags* insnFlags,
		int* pNewInstanceCount) {
	const int insnCount = dvmGetMethodInsnsSize(meth);
	const u2* insns = meth->insns;
	bool result = false;
	int i;

	*pNewInstanceCount = 0;

	for (i = 0; i < insnCount;) {
		int width;

		/*
		 * Switch tables are identified with "extended NOP" opcodes. They
		 * contain no executable code, so we can just skip past them.
		 */
		//some code here
	}
	bail: return result;
}
